#include "scanner.h"

#define SCAN1(sCond)			\
 	do {                        \
		c = *++cur;             \
	} while (sCond);
	
#define SCAN2(sCond, vCond)     \
	SCAN1(sCond)				\
	if (vCond)                  \
		return 0;


int comparator(const void *key, const void *elem);


void scanner(char *buff)
{
	src_buff = buff;
	
	init_token_buffer();

	int s;
	
    printf("inst:%d", bnf_instruction());
	
	print_tokens();
	
	free_token_buffer();
}

int comparator(const void *key, const void *elem)
{
	const INSTR *e = (INSTR*)elem;
	return strcmp((const char*)key, e->str);
}

int bnf_instruction()
{
	int s;
	
	if (s = bnf_lowname())
	{
		char *str = get_string(src_buff, s);
		INSTR *p = bsearch(str, instructions,
			sizeof(instructions) / sizeof(instructions[0]),
			sizeof(instructions[0]), comparator);
		if (p == 0)
			s = 0;
	}
	
	return s;
}


/* expression */

int bnf_expression(void)
{
	register int g;
	register int l;

	if (g = bnf_signed_term())
	{
		while (l = bnf_addop())
		{
			g += l;
			src_buff = save_token(TYPE_OPERATOR, src_buff, l);
			l = bnf_signed_term();
			if (!l)
			{
				g = 0;
				break;
			}
			else
			{
				g += l;
			}
		}
	}
	
	return g;
}

int bnf_signed_term(void)
{
	register int s;
	register int l;
	
	if (l = bnf_addop())
	{
		src_buff = save_token(TYPE_OPERATOR, src_buff, l);
	}
	
	if (s = bnf_term())
		s += l;
	else
		s = 0;
	
	return s;
}

int bnf_term()
{
	register int g;
	register int l;

	if (g = bnf_factor())
	{
		while (l = bnf_mulop())
		{
			g += l;
			src_buff = save_token(TYPE_OPERATOR, src_buff, l);
			l = bnf_signed_term();
			if (!l)
			{
				g = 0;
				break;
			}
			else
			{
				g += l;
			}
		}
	}
	
	return g;
}

int bnf_factor()
{
	int s;
	int l;
	
	if (s = bnf_id())
	{
	
	}
	else
	{
		if (l = match('('))
		{
			s += l;
			src_buff = save_token(0, src_buff, l);
			
			if (s = bnf_expression())
			{
				s += l;
			}
			
			if (s && (l = match(')')))
			{
				s += l;
				src_buff = save_token(0, src_buff, l);
			}
			else
			{
				return 0;
			}
		}
	}
	
	return s;
}

int bnf_mulop()
{
	skip_space();
	register char *cur = src_buff;
	return IS_MULOP(*cur);
}

int bnf_addop()
{
	skip_space();
	register char *cur = src_buff;
	return IS_ADDOP(*cur);
}


/* id, string*/

int bnf_id(void)
{
	int s;
	
	if (s = bnf_string())
	{
		src_buff = save_token(TYPE_STRING, src_buff, s);
	}
	else if (s = bnf_number())
	{
	
	}
	
	return s;
}

int bnf_string(void)
{
	skip_space();

	register char *cur = src_buff;
	register char token;
	
	if (*cur != '"' && *cur != '\'')
		return 0;
	
	token = *cur++;
	
	while (*cur != token)
	{
		if (*cur == -1)
		{
			cur -= 2;
			break;
		}
		cur++;
	}
	
	return cur - src_buff + 1;
}


/* Names */

// pattern [a-z][a-zA-Z0-9_]*
int bnf_name(void)
{
	skip_space();

	register char *cur = src_buff;
	
	if (!IS_LLETTER(*cur))
		return 0;

	while (IS_LET_OR_NUM_(*cur))
		cur++;
	
	return cur - src_buff;
}

// [a-z][a-z0-9]*
int bnf_lowname(void)
{
	skip_space();

	register char *cur = src_buff;
	
	if (!IS_LLETTER(*cur))
		return 0;

	while (IS_LLETTER(*cur))
		cur++;
	
	if (IS_ULETTER_(*cur) || IS_NUMBER(*cur))
		return 0;

	return cur - src_buff;
}

// [A-Z][A-Z0-9_]*
int bnf_capname(void)
{
	skip_space();

	register char *cur = src_buff;
	
	if (IS_US(*cur))
		return 0;

	while (IS_ULETTER_(*cur) || IS_NUMBER(*cur))
		cur++;
	
	if (IS_LLETTER(*cur))
		return 0;

	return cur - src_buff;
}


/* Numbers */

int bnf_number(void) 
{
    skip_space();

	int s;
	
    if (s = bnf_decimal())
    {
       src_buff = save_token(TYPE_NUMBER_DECIMAL, src_buff, s);
    }
    else if (s = bnf_binary())
    {
       src_buff = save_token(TYPE_NUMBER_BINARY, src_buff, s);
    }
    else if (s = bnf_hexadecimal())
    {
       src_buff = save_token(TYPE_NUMBER_HEXA, src_buff, s);
    }
    
    return s;
}

int bnf_decimal(void)
{
	register char *cur = src_buff;

	while (IS_NUMBER(*cur))
		cur++;
		
	if (IS_LETTER(*cur))
		return 0;

	return cur - src_buff;
}

int bnf_binary(void)
{
	register char *cur = src_buff;

    while (IS_BINARY(*cur))
		cur++;
	
	if (*cur != 'b')
		return 0;

	return cur - src_buff + 1;
}

int bnf_hexadecimal(void)
{
	register char *cur = src_buff;

    if (*cur != '0' && *(cur + 1) != 'x')
        return 0;

	cur++;
	cur++;
	
	while (IS_HEXA(*cur))
		cur++;
	
	int s = cur - src_buff;
	
	if (IS_LETTER(*cur) || s == 2)
		return 0;

	return s;
}


/* General */

inline int match(char c)
{
	return (*src_buff == c);
}

void skip_space(void)
{
	register char *cur = src_buff;

	while (IS_SPACE(*cur))
		cur++;
	
    src_buff = cur;
}


